#pragma once
#include <muduo/net/TcpServer.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/net/Buffer.h>
#include <muduo/net/EventLoop.h>
#include<muduo/net/TcpClient.h>
#include <muduo/net/TcpClient.h>
#include <muduo/net/EventLoopThread.h>
#include <iostream>
#include <unordered_map>
#include"abstract.hpp"
#include"detail.hpp"
#include"fileds.hpp"
#include"message.hpp"
#include<mutex>
#include<unordered_map>
namespace rpc
{
   class MuduoBuffer:public BaseBuffer
   {
   public:
       using ptr = std::shared_ptr<MuduoBuffer>;
       MuduoBuffer(muduo::net::Buffer*buff)
       :_buff(buff){}

       // 返回缓冲区中能读取的大小
       virtual size_t readAbleSiae() override
       {
           return _buff->readableBytes();
       }
       // 读取4个字节的内存大小
       virtual int32_t peekInt32() override
       { //muduo是一个网络库，从缓存区取出来的数据会被网络转换
           return _buff->peekInt32();
       }
       // 删除四个字节大小
       virtual void retriveInt32() override
       {
            _buff->retrieveInt32();
       }
       // 读取并删除
       virtual int32_t readInt32() override
       {
           return _buff->readInt32();
       }
       // 读取指定长度的缓存并转化为string类型
       virtual std::string retriveAsString(size_t len) override
       {
           return _buff->retrieveAsString(len);
       }

    private:
        muduo::net::Buffer *_buff;
   };

   class BufferFactory
   {
      public:
         template<typename ...Args>
        static BaseBuffer::ptr create( Args&&...args)
        {
            return std::make_shared<MuduoBuffer>(std::forward<Args>(args)...);
        }
   };

   class LVProtocol:public BaseProtocol
   {
      public:
         using ptr = std::shared_ptr<LVProtocol>;
         // 判断消息的长度是否可以处理
         //LEN--value
         //totallen---type---
         virtual bool canProcessed(const BaseBuffer::ptr &buff) override
         {
              if(buff->readAbleSiae()<totalFieldLenth)
              {
                  return false;
              }

             int total_len = buff->peekInt32();
             delog("total_len:%d", total_len);
             if (buff->readAbleSiae() < total_len + totalFieldLenth)
             {
                 errlog("消息长度过长，读取错误");
                 return false;
             }
             return true;
         }
         // 处理消息，还给一个消息
         virtual bool onMessage(const BaseBuffer::ptr &buff, BaseMessage::ptr& msg) override
         {
            //处理之前默认可以读取缓冲区
            //totallen---mytype---idlenth----id---body
           // delog("buff:");
            
            int32_t totalLenth = buff->readInt32();
            MY_TYPE mytype = (MY_TYPE)buff->readInt32();
            int32_t idlenth = buff->readInt32();
            //读取id
            std::string id = buff->retriveAsString(idlenth);
            //body的长度
            int32_t bodyLenth = totalLenth - idlenth - mytypeFieldLenth-idFieldLenth;
            std::string body = buff->retriveAsString(bodyLenth);
            // errlog("body:%s", body.c_str());
            //  std::cout << body << std::endl;
            delog("totalLenth:%d", totalLenth);
            delog("idLenth:%d", idlenth);
            delog("bodyLenth:%d", bodyLenth);
           // std::cout << "mytype:"<<(int)mytype << std::endl;
            // 将处理好的消息带出
            
           msg = MessageFactory::create(mytype);
            if(msg.get() == nullptr)
            {
                errlog("构造的对象为空");
                return false;
            }
          
            bool ret = msg->unserilize(body);//body的问题
         
            if (ret == false)
            {
                errlog("消息正文反序列化失败");
                return false;
            }

            msg->setId(id);
            msg->setMytype(mytype);

            return true;
         }
         // 序列化消息：要按照协议序列化,序列化后返回一个字符串
         virtual std::string searilize(const BaseMessage::ptr &msg) override
         {
            std::string body = msg->serilize();
            std::string id = msg->getId();
            auto mtype = htonl((int32_t)msg->getMytype());
            int32_t idlen = htonl(id.size());
            int32_t h_total_len =  mytypeFieldLenth+idFieldLenth + id.size() + body.size();
            int32_t n_total_len = htonl(h_total_len);
            delog("h_total_len:%d", h_total_len);
            std::string result;
            result.reserve(h_total_len);
            result.append((char *)&n_total_len, totalFieldLenth);
            result.append((char *)&mtype, mytypeFieldLenth);
            result.append((char *)&idlen, idFieldLenth);
            result.append(id);
            result.append(body);

            delog("result:");
            std::cout << result << std::endl;
            return result;
         }

      private:
           const size_t  totalFieldLenth = 4;
           const size_t mytypeFieldLenth = 4;
           const size_t idFieldLenth = 4;
   };

   class ProtocolFactory
   {
   public:
       template <typename... Args>
       static BaseProtocol::ptr create( Args &&...args)
       {
           return std::make_shared<LVProtocol>(std::forward<Args>(args)...);
       }
   };

   class MuduoConnection:public BaseConnection
   {
   public:
       using ptr = std::shared_ptr<MuduoConnection>;
       MuduoConnection(const BaseProtocol::ptr protocol,const muduo::net::TcpConnectionPtr&conn)
       :_protocol(protocol),
        _conn(conn){}
       // 发送消息
       virtual bool send(const BaseMessage::ptr &msg) override
       {
           //先将消息用协议序列化出来
           delog("开始发送消息");
           std::string body = _protocol->searilize(msg);
           _conn->send(body);
           return true;
       }
       // 连接
       virtual bool connect() override
       {
           return _conn->connected();
       }
       // 关闭连接
       virtual void disConnect() override
       {
           _conn->shutdown();
       }

    private:
        BaseProtocol::ptr _protocol;
        muduo::net::TcpConnectionPtr _conn;
   };

   class ConnectionFactory
   {
   public:
       template <typename ...Args>
       static BaseConnection::ptr create(Args &&...args)
       {
           return std::make_shared<MuduoConnection>(std::forward<Args>(args)...);
       }
   };

   //实现MuduoServer
   class  MuduoServer:public BaseServer
   {
   public:
       using ptr = std::shared_ptr<MuduoServer>;
       MuduoServer(int port)
           : _server(&_baseloop,
            muduo::net::InetAddress("0.0.0.0", port), 
           "MuduoServer",
            muduo::net::TcpServer::kReusePort),
            _protocol(ProtocolFactory::create())
           {}
        // 实现start
       virtual void start() override
       {
           // 设置连接事件
           _server.setConnectionCallback(std::bind(&MuduoServer::onConnection, this, std::placeholders::_1));
           // 设置消息回应事件
           _server.setMessageCallback(std::bind(&MuduoServer::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
           //开始事件服务
           _server.start();
           //开始事件循环
           _baseloop.loop();
       }

   private:
       void onConnection(const muduo::net::TcpConnectionPtr &conn)
       {    
            //如果有连接，那就创建muduo连接并使用哈希表管理起来
           if (conn->connected())
           {
               delog("连接建立成功");
              
             
               //建立conn与tcp连接的关系
              auto muduoconn = ConnectionFactory::create(_protocol,conn);
               {
                   std::unique_lock<std::mutex> _lock(_mutex);
                   _conns.insert({conn,muduoconn});
               }
               
               //如果设置了连接回调，那就执行连接回调
               if(_cb_connection)
                   _cb_connection(muduoconn);
           }
           else
           {
               infolog("连接建立失败");
               BaseConnection::ptr muduo_conn;//为了下面执行回调
               {
                   std::unique_lock<std::mutex> lock(_mutex);
                   auto it = _conns.find(conn);
                   if(it == _conns.end())
                   {
                       return;
                   }
                   muduo_conn = it->second;
                   _conns.erase(conn);
               }
               //如果调用了关闭回调，那就关闭
                if(_cb_close)
                       _cb_close(muduo_conn);
           }
       }

       void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buff, const muduo::Timestamp &stamp)
       {
           //循环处理事件
           delog("有新消息");
           auto base_buf = BufferFactory::create(buff);
           delog("base_buf:%ld", base_buf->readAbleSiae());
        //   std::cout << base_buf->retriveAsString(base_buf->readAbleSiae()) << std::endl;
           while (1)
           {
               //根据协议层判断数据是否能够处理
               if(_protocol->canProcessed(base_buf) == false)
               {   
                   
                   //特殊情况：缓冲区内的内容大于最大值
                   if(base_buf->readAbleSiae()>_maxSize)
                   {
                       errlog("缓冲区数据过大");
                       conn->shutdown();//断开连接
                       break;
                   }
                   errlog("数据量不足");
                   break;
               }

               delog("缓冲区可以处理");

               //如果缓冲区内的数据能够处理，那就处理
               BaseMessage::ptr msg;
               // 处理数据，但是要判断数据格式是否正确
               bool ret = _protocol->onMessage(base_buf,msg);
               
               if(ret == false)
               {
                   errlog("缓冲区数据错误");
                   conn->shutdown();
                   return;
               }

               // 数据可以处理并且格式正确：找到对应的BaseBuffer对象
               // 构造base_buf对象
               delog("消息可以处理");
               BaseConnection::ptr base_conn;
               {
                   std::unique_lock<std::mutex> lock(_mutex);
                   auto it = _conns.find(conn);
                   if(it == _conns.end())
                   {
                      conn->shutdown();//关闭连接
                      return;
                   }
                   base_conn = it->second;//找到连接，开始调用
               }

               if(_cb_message)
                 {
                     delog("开始处理");
                     _cb_message(base_conn, msg);
                      delog("处理完毕");
                 }
           }
       }

       const int _maxSize = 1 << 16;//设置读取的最大值
       muduo::net::EventLoop _baseloop;
       muduo::net::TcpServer _server;
       //管理连接
       std::unordered_map<muduo::net::TcpConnectionPtr, BaseConnection::ptr>_conns;
       // 加锁:在操作管理连接的哈希表时要加上锁
       std::mutex _mutex;
       BaseProtocol::ptr _protocol;//创建MuduoConnection时要是有protocol
   };

   class ServerFactory
   {
   public:
       template <typename... Args>
       static BaseServer::ptr create( Args &&...args)
       {
           return std::make_shared<MuduoServer>(std::forward<Args>(args)...);
       }
   };

   // MuduoClient
   // 设置服务端抽象:设置好回调+连接+关闭+是否连接正常+发送消息
   class MuduoClient:public BaseClient
   {
   public:
       using ptr = std::shared_ptr<MuduoClient>;
       MuduoClient(const std::string &sip, const int& sport)
           : _client(_baseloop, muduo::net::InetAddress(sip, sport), "MuduoClient"),
             _downtach(1),
             _protocol(ProtocolFactory::create()),
             _baseloop(_loop.startLoop()){}
       // 连接函数
       virtual void connect() override
       { // 开始设置连接回调
           _client.setConnectionCallback(std::bind(&MuduoClient::onConnection, this, std::placeholders::_1));
           // 设置消息回调
           _client.setMessageCallback(std::bind(&MuduoClient::onMessage, this, std::placeholders::_1,
                                                std::placeholders::_2, std::placeholders::_3));
           // 开始连接，连接是异步的所以要配合downtach来进行异步等待避免提前send
           _client.connect();
           // downtach等待
           _downtach.wait();
       }
       // 关闭函数
       virtual void shutdown()
       {
           _client.disconnect();
       }
       // 判断连接是否正常
       virtual bool connected()
       {
           return _conn && _conn->connect();
       }
       // 发送数据
       virtual bool send(const BaseMessage::ptr &msg)
       { 
            if(!_conn)
            {
                errlog("连接断开");
                return false;
            }
            
            return _conn->send(msg);
       }
       // 获取连接对象
       virtual BaseConnection::ptr connection()
       {
           return _conn;
       }

   private:
       void onConnection(const muduo::net::TcpConnectionPtr& conn)
       {
           if (!conn->connected())
           {
               errlog("连接建立失败");
               _conn.reset();
           }
           else
           {
               // downtach计数减一
               infolog("连接建立成功");
               _downtach.countDown();
               _conn = ConnectionFactory::create(_protocol,conn);
           }
       }

       void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *_buff, const muduo::Timestamp &stamp)
       {
           // 循环处理事件
           BaseBuffer::ptr base_buf = BufferFactory::create(_buff);
           while (1)
           {
               // 根据协议层判断数据是否能够处理
               if (_protocol->canProcessed(base_buf) == false)
               {
                   // 特殊情况：缓冲区内的内容大于最大值
                   if (base_buf->readAbleSiae() >_maxSize)
                   {
                       errlog("缓冲区数据过大");
                       conn->shutdown(); // 断开连接
                       break;
                   }

                   break;
               }

               // 如果缓冲区内的数据能够处理，那就处理
               BaseMessage::ptr msg;
               // 处理数据，但是要判断数据格式是否正确
               bool ret = _protocol->onMessage(base_buf, msg);
               if (ret == false)
               {
                   errlog("缓冲区数据错误");
                   conn->shutdown();
                   return;
               }
                
               if (_cb_message)
                  {
                      _cb_message(_conn, msg);
                  }
           }
       }

   private:
       BaseProtocol::ptr _protocol;
       muduo::net::EventLoopThread _loop; // 用来进行事件的监听，使用其它线程开启，为了避免无限循环
       muduo::net::EventLoop *_baseloop;
       BaseConnection::ptr _conn;
       muduo::CountDownLatch _downtach;
       muduo::net::TcpClient _client;
       const int _maxSize = 1<<16;
   };

   class ClientFactory
   {
   public:
       template <typename... Args>
       static BaseClient::ptr create(Args &&...args)
       {
           return std::make_shared<MuduoClient>(std::forward<Args>(args)...);
       }
   };
}